package org.jsola.hr.service.impl;

import org.jsola.admin.entity.ModuleSubjectTypeDO;
import org.jsola.admin.query.ModuleSubjectTypeQuery;
import org.jsola.admin.service.IModuleSubjectTypeService;
import org.jsola.admin.vo.ModuleSubjectTypeListVO;
import org.jsola.common.PageKit;
import org.jsola.core.Page;
import org.jsola.exception.ParamException;
import org.jsola.hr.common.ExampleKit;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.dao.IHrRoleDAO;
import org.jsola.hr.dto.HrRoleAddDTO;
import org.jsola.hr.dto.HrRoleUpdateDTO;
import org.jsola.hr.entity.HrRoleDO;
import org.jsola.hr.provider.IPermissionProviderService;
import org.jsola.hr.query.HrRoleQuery;
import org.jsola.hr.service.IHrPermissionService;
import org.jsola.hr.service.IHrRoleService;
import org.jsola.hr.vo.HrRoleListVO;
import org.jsola.hr.vo.HrRoleVO;
import org.jsola.permission.constant.PermissionConstants;
import org.jsola.permission.dto.RoleAddDTO;
import org.jsola.permission.dto.RoleUpdateDTO;
import org.jsola.permission.entity.RoleDO;
import org.jsola.permission.exception.PermissionException;
import org.jsola.permission.query.RoleQuery;
import org.jsola.permission.vo.RoleListVO;
import org.jsola.permission.vo.RoleVO;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.stream.Collectors;

import static org.jsola.hr.constant.HrPermissionConstants.*;

/**
 * 人力角色表
 *
 * @author zhr
 */
@Service("hrHrRoleServiceImpl")
public class HrRoleServiceImpl implements IHrRoleService {

    @Autowired
    private IHrRoleDAO hrRoleDAO;
    @Autowired
    private IHrPermissionService hrPermissionService;
    @Autowired
    private IPermissionProviderService permissionProviderService;

    @Autowired
    private IModuleSubjectTypeService moduleSubjectTypeService;

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public HrRoleVO save(HrRoleAddDTO hrRoleAddDTO, TokenUser tokenUser) {
        // 权限校验
        PermissionException.isTrue(hrPermissionService.hasRight(tokenUser.getUserId()
                , tokenUser.getSiteId(), HR_ENTERPRISESETUP_ROLEMANAGEMENT), PERMISSION_DENIED_MESSAGE);

        // 角色Ids;多个,隔开
        StringBuilder roleIds = new StringBuilder();
        // 分别创建操作端和管理端角色
        String[] subjectTypeList = {COMPANY_SUBJECT_TYPE, HR_SUBJECT_TYPE};
        for (int i = 0; i < subjectTypeList.length; i++) {
            RoleAddDTO roleAddDTO = hrRoleAddDTO.to(RoleAddDTO.class);
            roleAddDTO.setSubjectType(subjectTypeList[i]);
            roleAddDTO.setSubjectId(PermissionConstants.DEFAULT_SUBJECT_ID);
            roleAddDTO.setType("U");
            RoleVO roleVO = permissionProviderService.addRole(roleAddDTO, tokenUser);
            if (i > 0) {
                roleIds.append(",");
            }
            roleIds.append(roleVO.getId());
        }
        HrRoleDO hrRoleDO = hrRoleAddDTO.to(HrRoleDO.class);
        hrRoleDO.setRoleIds(roleIds.toString());
        hrRoleDO = save(hrRoleDO, tokenUser.getSiteId(), tokenUser.getUserId());
        return hrRoleDO.to(HrRoleVO.class);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(HrRoleUpdateDTO hrRoleUpdateDTO, TokenUser tokenUser) {
        HrRoleVO hrRoleVO = selectById(hrRoleUpdateDTO.getId(), tokenUser.getSiteId());
        ParamException.notNull(hrRoleVO, "修改的角色信息有误，请刷新后重试");
        //转DO
        HrRoleDO hrRoleDO = hrRoleUpdateDTO.to(HrRoleDO.class);
        // 角色Id不会修改 只能删除
        hrRoleDO.setRoleIds(null);
        String roleIdString = hrRoleVO.getRoleIds();
        // 修改人力角色名称后 同步修改后台角色名称
        if (!hrRoleVO.getName().equals(hrRoleUpdateDTO.getName()) && StringUtils.hasLength(roleIdString)) {
            List<Long> roleIds = Arrays.stream(roleIdString.split(",")).map(Long::parseLong).collect(Collectors.toList());
            List<RoleDO> roleDOList = permissionProviderService.selectRoleByIds(roleIds, tokenUser.getSiteId());
            for (RoleDO roleDO : roleDOList) {
                RoleUpdateDTO roleUpdateDTO = roleDO.to(RoleUpdateDTO.class);
                roleUpdateDTO.setName(hrRoleUpdateDTO.getName());
                roleUpdateDTO.setDescription(hrRoleUpdateDTO.getDescription());
                permissionProviderService.updateRole(roleUpdateDTO, tokenUser);
            }
        }
        //根据主键更新，只更新非null值
        return updateByIdSelective(hrRoleDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, Long... hrRoleIds) {
        List<HrRoleDO> hrRoleDOList = selectDOByIds(Arrays.asList(hrRoleIds), tokenUser.getSiteId());
        if (CollectionUtils.isEmpty(hrRoleDOList)) {
            return 0;
        }
        // 删除人力角色对应的角色
        List<Long> deleteRloeIds = new ArrayList<>();
        for (HrRoleDO hrRoleDO : hrRoleDOList) {
            String[] split = hrRoleDO.getRoleIds().split(",");
            if (split.length > 0) {
                List<Long> roleIds = Arrays.stream(split).map(Long::parseLong).collect(Collectors.toList());
                deleteRloeIds.addAll(roleIds);
            }
        }
        permissionProviderService.deleteRoleByIds(tokenUser, deleteRloeIds.toArray(new Long[0]));
        return logicalDeleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) hrRoleIds);
    }


    @Override
    public HrRoleVO selectById(Long hrRoleId, String siteId) {
        HrRoleDO hrRoleDO = selectDOById(hrRoleId, siteId);
        if (hrRoleDO == null) {
            return null;
        }
        return hrRoleDO.to(HrRoleVO.class);
    }

    @Override
    public HrRoleDO selectByRoleId(Long roleId, String siteId) {
        Example example = new Example(HrRoleDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andCondition("FIND_IN_SET('" + roleId + "' , role_ids)");
        return hrRoleDAO.selectOneByExample(example);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public List<HrRoleListVO> selectAndInitialization(HrRoleQuery hrRoleQuery, TokenUser tokenUser) {
        List<HrRoleDO> hrRoleDOList = selectDO(hrRoleQuery, tokenUser.getSiteId());
        if (CollectionUtils.isEmpty(hrRoleDOList)) {
            hrRoleDOList = new ArrayList<>();
            // 查询为空时查询原体统的公司角色 若存在 创建对应的人力角色
            RoleQuery roleQuery = hrRoleQuery.to(RoleQuery.class);
            roleQuery.setSubjectType(COMPANY_SUBJECT_TYPE);
            List<RoleListVO> roleListVOList = permissionProviderService.queryRoleList(roleQuery, tokenUser.getSiteId());
            if (!CollectionUtils.isEmpty(roleListVOList)) {
                for (RoleListVO roleListVO : roleListVOList) {
                    // 创建管理端同名角色
                    RoleAddDTO roleAddDTO = roleListVO.to(RoleAddDTO.class);
                    roleAddDTO.setSubjectType(HR_SUBJECT_TYPE);
                    roleAddDTO.setSubjectId(PermissionConstants.DEFAULT_SUBJECT_ID);
                    roleAddDTO.setType("U");
                    RoleVO roleVO = permissionProviderService.addRole(roleAddDTO, tokenUser);
                    HrRoleDO hrRoleDO = roleListVO.to(HrRoleDO.class);
                    hrRoleDO.setRoleIds(roleListVO.getId() + "," + roleVO.getId());
                    hrRoleDO.setId(null);
                    hrRoleDO = save(hrRoleDO, tokenUser.getSiteId(), tokenUser.getUserId());
                    hrRoleDOList.add(hrRoleDO);
                }
            }
        }
        // 原子权限数量(管理端hr  操作端+增值服務（hr下的子模块）)
        Map<String, Long> countMap = permissionProviderService
                .getRoleRightCountMap("hr", tokenUser.getSiteId());

        ModuleSubjectTypeQuery moduleSubjectTypeQuery = new ModuleSubjectTypeQuery();
        moduleSubjectTypeQuery.setModuleType("hr");
        List<ModuleSubjectTypeListVO> list = moduleSubjectTypeService.select(moduleSubjectTypeQuery, tokenUser.getSiteId());
        List<String> subjectTypeList = list.stream().map(ModuleSubjectTypeListVO::getSubjectType).collect(Collectors.toList());
        Map<String, Long> otherCountMap = permissionProviderService
                .getRoleRightCountMap(subjectTypeList, tokenUser.getSiteId());


        return hrRoleDOList.parallelStream().map(hrRoleDO -> {
            HrRoleListVO hrRoleListVO = hrRoleDO.to(HrRoleListVO.class);
            String[] split = hrRoleListVO.getRoleIds().split(",");
            // 查询角色表中人力角色对应的角色
            if (split.length > 0) {
                List<Long> roleIds = Arrays.stream(split).map(Long::parseLong).collect(Collectors.toList());
                List<RoleDO> roleDOList = permissionProviderService.selectRoleByIds(roleIds, tokenUser.getSiteId());
                // 无权限的跳过
                if (CollectionUtils.isEmpty(roleDOList)) {
                    return null;
                }
                // 组成list
                List<RoleVO> roleVOList = new ArrayList<>();
                // 操作端权限校验
                boolean hadCompany = false;
                // 管理端权限校验
                boolean hadHr = false;
                long permissionCount = 0L;
                long otherPermissionCount = 0L;
                for (RoleDO roleDO : roleDOList) {
                    if (COMPANY_SUBJECT_TYPE.equals(roleDO.getSubjectType())) {
                        hadCompany = true;
                    }
                    // 管理端角色
                    else if (HR_SUBJECT_TYPE.equals(roleDO.getSubjectType())) {
                        hadHr = true;
                    }
                    RoleVO roleVO = roleDO.to(RoleVO.class);
                    roleVOList.add(roleVO);
                    permissionCount += countMap.get(roleDO.getId() + "") == null ? 0L : countMap.get(roleDO.getId() + "");
                    otherPermissionCount += otherCountMap.get(roleDO.getId() + "") == null ? 0L : otherCountMap.get(roleDO.getId() + "");
                }
                // 缺少操作端/管理端角色 过滤
                if (!hadCompany || !hadHr) {
                    return null;
                }
                hrRoleListVO.setRoleVOList(roleVOList);
                hrRoleListVO.setPermissionCount(permissionCount + otherPermissionCount);
            } else {
                return null;
            }
            return hrRoleListVO;
        }).filter(Objects::nonNull).parallel().collect(Collectors.toList());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public HrRoleVO selectChannelHrRole(TokenUser tokenUser) {
        Example example = new Example(HrRoleDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andEqualTo("name", "渠道");
        example.orderBy("gmtCreate");
        List<HrRoleDO> hrRoleDOList = hrRoleDAO.selectByExample(example);
        if (CollectionUtils.isEmpty(hrRoleDOList)) {
            HrRoleAddDTO hrRoleAddDTO = new HrRoleAddDTO();
            hrRoleAddDTO.setName("渠道");
            return save(hrRoleAddDTO, tokenUser);
        }
        return hrRoleDOList.get(0).to(HrRoleVO.class);
    }

    @Override
    public Page<HrRoleListVO> selectAndInitializationPage(HrRoleQuery hrRoleQuery, TokenUser tokenUser) {
        List<HrRoleListVO> hrRoleListVOList = selectAndInitialization(hrRoleQuery, tokenUser);
        return PageKit.startPage(hrRoleListVOList, hrRoleQuery.getPageNo(), hrRoleQuery.getPageSize());
    }

    @Override
    public int selectCount(HrRoleQuery hrRoleQuery, String siteId) {
        Example example = buildExample(hrRoleQuery, siteId);
        return hrRoleDAO.selectCountByExample(example);
    }

    @Override
    public Page<HrRoleListVO> selectPage(HrRoleQuery hrRoleQuery, String siteId) {
        Example example = buildExample(hrRoleQuery, siteId);
        Page<HrRoleDO> page = hrRoleDAO.selectPageByExample(example,
                hrRoleQuery.getPageNo(),
                hrRoleQuery.getPageSize());

        return page.to(HrRoleListVO.class);
    }

    @Override
    public HrRoleDO selectDOById(Long hrRoleId, String siteId) {
        return listById(hrRoleId, siteId);
    }

    private List<HrRoleDO> selectDOByIds(List<Long> hrRoleIds, String siteId) {
        if (CollectionUtils.isEmpty(hrRoleIds)) {
            return new ArrayList<>();
        }
        Example example = new Example(HrRoleDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andIn("id", hrRoleIds);
        return hrRoleDAO.selectByExample(example);
    }

    @Override
    public List<HrRoleDO> selectDO(HrRoleQuery hrRoleQuery, String siteId) {
        Example example = buildExample(hrRoleQuery, siteId);
        return hrRoleDAO.selectByExample(example);
    }


    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public Integer deleteRoles(List<Long> roleIds, TokenUser tokenUser) {
        ParamException.notEmpty(roleIds, "请选择角色");
        ParamException.notNull(tokenUser.getSiteId(), "站点id不能为空");

        roleIds.parallelStream().forEach(roleId -> {
            Example example = new Example(HrRoleDO.class);
            example.and()
                    .andEqualTo("valid", true)
                    .andCondition("FIND_IN_SET('" + roleId + "' , roleIds)");
            List<HrRoleDO> hrRoleDOList = hrRoleDAO.selectByExample(example);
            ParamException.isTrue(CollectionUtils.isEmpty(hrRoleDOList), "该角色已创建操作端角色，请前往管理端删除");
        });

        return new Long(roleIds.stream().peek(roleId
                -> permissionProviderService.deleteRoleById(roleId, tokenUser)).count()).intValue();
    }

    @Override
    public List<String> selectByCode(String code, String siteId) {
        List<String> result = new ArrayList<>();
        Example example = new Example(HrRoleDO.class);
        example.and()
                .andEqualTo("code", code)
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        List<HrRoleDO> list = hrRoleDAO.selectByExample(example);
        if (CollectionUtils.isEmpty(list)) {
            return result;
        } else {
            for (HrRoleDO hrRoleDO : list) {
                String roleIds = hrRoleDO.getRoleIds();
                if (org.apache.commons.lang3.StringUtils.isNotBlank(roleIds)) {
                    String[] roleArr = roleIds.split(",");
                    result.addAll(Arrays.asList(roleArr));
                }
            }
            return result;
        }
    }

    @Override
    public List<String> selectByCodeList(List<String> codeList, String siteId) {
        List<String> result = new ArrayList<>();
        Example example = new Example(HrRoleDO.class);
        example.and()
                .andIn("code", codeList)
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        List<HrRoleDO> list = hrRoleDAO.selectByExample(example);
        if (CollectionUtils.isEmpty(list)) {
            return result;
        } else {
            for (HrRoleDO hrRoleDO : list) {
                String roleIds = hrRoleDO.getRoleIds();
                if (org.apache.commons.lang3.StringUtils.isNotBlank(roleIds)) {
                    String[] roleArr = roleIds.split(",");
                    result.addAll(Arrays.asList(roleArr));
                }
            }
            return result;
        }
    }

    /**
     * 根据查询参数，构建example
     *
     * @param hrRoleQuery 查询参数
     * @param siteId      所属站点id
     * @return example
     */
    private Example buildExample(HrRoleQuery hrRoleQuery, String siteId) {
        Example example = new Example(HrRoleDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        if (hrRoleQuery.getName() != null) {
            example.and().andLike("name", "%" + hrRoleQuery.getName() + "%");
        }
        if (hrRoleQuery.getCode() != null) {
            example.and().andEqualTo("code", hrRoleQuery.getCode());
        }
        if (hrRoleQuery.getReserveFlag() != null) {
            example.and().andEqualTo("reserveFlag", hrRoleQuery.getReserveFlag());
        }
        // 排序
        ExampleKit.setExampleOrder(example, hrRoleQuery.getOrders());
        return example;
    }
}




